package com.fate.system.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fate.framework.exception.KKException;
import com.fate.framework.utils.CommonUtil;
import com.fate.system.constant.QuartzJobConst;
import com.fate.system.entity.QuartzJob;
import com.fate.system.service.IQuartzJobService;
import com.fate.system.mapper.QuartzJobMapper;
import jakarta.annotation.Resource;
import org.quartz.*;
import org.springframework.stereotype.Service;
import com.fate.framework.utils.SystemUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fate.system.dto.quartzjob.QuartzJobPageDTO;

import java.util.List;

/**
 * @author 47349
 * @description 针对表【sys_quartz_job(定时任务)】的数据库操作Service实现
 * @createDate 2024-08-18 23:56:12
 */
@Service
public class QuartzJobServiceImpl extends ServiceImpl<QuartzJobMapper, QuartzJob>
    implements IQuartzJobService {

  @Resource private QuartzJobMapper quartzJobMapper;
  @Resource private Scheduler scheduler;

  public Page<QuartzJob> getPageList(QuartzJobPageDTO pageDTO) {
    String jobName = pageDTO.getJobName();
    Integer status = pageDTO.getStatus();
    Page<QuartzJob> page = SystemUtil.buildPageFromDTO(pageDTO, QuartzJob.class);
    return this.lambdaQuery()
        .like(CommonUtil.notNullOrEmpty(jobName), QuartzJob::getJobName, jobName)
        .eq(CommonUtil.notNullOrEmpty(status), QuartzJob::getStatus, status)
        .orderByDesc(QuartzJob::getGmtCreate)
        .page(page);
  }

  @Override
  public void saveAndScheduleJob(QuartzJob quartzJob) {
    if (QuartzJobConst.STATUS_NORMAL.equals(quartzJob.getStatus())) {
      // 定时器添加
      this.schedulerAdd(
          quartzJob.getJobClassName().trim(),
          quartzJob.getCronExpression().trim(),
          quartzJob.getParameter());
    }
    // DB设置修改
    this.save(quartzJob);
  }

  @Override
  public void editAndScheduleJob(QuartzJob quartzJob) throws SchedulerException {
    if (QuartzJobConst.STATUS_NORMAL.equals(quartzJob.getStatus())) {
      schedulerDelete(quartzJob.getJobClassName().trim());
      schedulerAdd(
          quartzJob.getJobClassName().trim(),
          quartzJob.getCronExpression().trim(),
          quartzJob.getParameter());
    } else {
      scheduler.pauseJob(JobKey.jobKey(quartzJob.getJobClassName().trim()));
    }
    this.updateById(quartzJob);
  }

  @Override
  public void deleteAndStopJob(QuartzJob quartzJob) {
    schedulerDelete(quartzJob.getJobClassName().trim());
    this.removeById(quartzJob.getId());
  }

  @Override
  public void resumeJob(QuartzJob quartzJob) {
    schedulerDelete(quartzJob.getJobClassName().trim());
    schedulerAdd(
        quartzJob.getJobClassName().trim(),
        quartzJob.getCronExpression().trim(),
        quartzJob.getParameter());
    quartzJob.setStatus(QuartzJobConst.STATUS_NORMAL);
    this.updateById(quartzJob);
  }

  @Override
  public List<QuartzJob> getRunJobList() {
    return this.lambdaQuery().eq(QuartzJob::getStatus, QuartzJobConst.STATUS_NORMAL).list();
  }

  /** 添加定时任务 */
  private void schedulerAdd(String jobClassName, String cronExpression, String parameter) {
    try {
      // 启动调度器
      scheduler.start();

      // 构建job信息
      JobDetail jobDetail =
          JobBuilder.newJob(getClass(jobClassName).getClass())
              .withIdentity(jobClassName)
              .usingJobData("parameter", parameter)
              .build();

      // 表达式调度构建器(即任务执行的时间)
      CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

      // 按新的cronExpression表达式构建一个新的trigger
      CronTrigger trigger =
          TriggerBuilder.newTrigger()
              .withIdentity(jobClassName)
              .withSchedule(scheduleBuilder)
              .build();

      scheduler.scheduleJob(jobDetail, trigger);
    } catch (SchedulerException e) {
      throw new KKException("创建定时任务失败", e);
    } catch (RuntimeException e) {
      throw new KKException(e.getMessage(), e);
    } catch (Exception e) {
      throw new KKException("后台找不到该类名：" + jobClassName, e);
    }
  }

  /** 删除定时任务 */
  private void schedulerDelete(String jobClassName) {
    try {
      /*使用给定的键暂停Trigger 。*/
      scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName));
      /*从调度程序中删除指示的Trigger */
      scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName));
      /*从 Scheduler 中删除已识别的Job - 以及任何关联的Trigger */
      scheduler.deleteJob(JobKey.jobKey(jobClassName));
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      throw new KKException("删除定时任务失败");
    }
  }

  private static Job getClass(String classname) throws Exception {
    Class<?> class1 = Class.forName(classname);
    return (Job) class1.getDeclaredConstructor().newInstance();
  }
}
